package top.lunarye.modules.award.controller;


import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.annotation.SaCheckRole;
import cn.dev33.satoken.annotation.SaMode;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.*;

import org.springframework.web.multipart.MultipartFile;
import springfox.documentation.annotations.ApiIgnore;
import top.lunarye.annotation.TokenToStaff;
import top.lunarye.modules.award.entity.Award;
import top.lunarye.modules.award.entity.dto.AwardInsertDTO;
import top.lunarye.modules.award.entity.dto.AwardPageDTO;
import top.lunarye.modules.award.entity.dto.AwardSelectDTO;
import top.lunarye.modules.award.entity.dto.AwardUpdateDTO;
import top.lunarye.modules.award.service.IAwardService;
import top.lunarye.modules.file.entity.File;
import top.lunarye.modules.file.service.IFileService;
import top.lunarye.modules.staff.entity.RoleEnum;
import top.lunarye.modules.staff.entity.Staff;
import top.lunarye.modules.staff.service.IStaffService;
import top.lunarye.utils.RestResponse;
import top.lunarye.utils.SystemCode;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 成果表  前端控制器
 * </p>
 *
 * @author lunar
 * @since 2021-07-23
 */
@RestController
@Api(tags = "奖项模块")
@RequestMapping("/award")
@SaCheckLogin
public class AwardController {
    @Autowired
    @Qualifier("AwardServiceImpl")
    private IAwardService awardService;

    @Autowired
    @Qualifier("FileServiceImpl")
    private IFileService fileService;

    @Autowired
    @Qualifier("StaffServiceImpl")
    private IStaffService staffService;

    @GetMapping
    @ApiOperation("用于获取奖项列表")
    public RestResponse<List<Award>> getList(@ApiIgnore @TokenToStaff Staff loginStaff){
        List<Award> list = awardService.list();
        return RestResponse.ok(list);
    }

    @PostMapping
    @ApiOperation("添加奖项")
    public RestResponse<String> insertAward(@RequestBody AwardInsertDTO awardInsertDTO,
                                            @ApiIgnore @TokenToStaff Staff loginStaff) {
        Award insertAward = Award.builder().build();
        BeanUtils.copyProperties(awardInsertDTO, insertAward);
        insertAward.setStaffId(loginStaff.getId());
        boolean save = awardService.save(insertAward);
        if (save) {
            return RestResponse.ok();
        } else {
            return RestResponse.fail(SystemCode.InnerError.getCode(), "存储信息时发生错误");
        }
    }

    @PostMapping("add")
    @ApiOperation("上传文件列表添加奖项")
    public RestResponse<String> addAward(MultipartFile[] images, MultipartFile[] files, String title, Date getTime,
                                         String content, String type, @ApiIgnore @TokenToStaff Staff loginStaff) {
        List<Integer> addedImages = new LinkedList<>();
        if (images != null && images.length != 0)
            for (MultipartFile image : images) {
                RestResponse<Integer> imageAddResult = fileService.uploadFile(image, "image", loginStaff);
                if (imageAddResult.getCode() == 1) {
                    addedImages.add(imageAddResult.getResponse());
                } else {
                    for (Integer addedFile : addedImages) {
                        fileService.deleteById(addedFile, loginStaff);
                    }
                    return RestResponse.fail(SystemCode.InnerError.getCode(), "存储文件时发生错误");
                }
            }
        List<Integer> addedFiles = new LinkedList<>();
        if (files != null && files.length != 0)
            for (MultipartFile file: files) {
                RestResponse<Integer> imageAddResult = fileService.uploadFile(file, "image", loginStaff);
                if (imageAddResult.getCode() == 1) {
                    addedFiles.add(imageAddResult.getResponse());
                } else {
                    for (Integer addedImage: addedImages) {
                        fileService.deleteById(addedImage, loginStaff);
                    }
                    for (Integer addedFile : addedFiles) {
                        fileService.deleteById(addedFile, loginStaff);
                    }
                    return RestResponse.fail(SystemCode.InnerError.getCode(), "存储文件时发生错误");
                }
            }

        // 已经添加的文件的id列表json字串
        String addedImagesJson = JSONUtil.parse(addedImages).toJSONString(0);
        String addedFilesJson = JSONUtil.parse(addedFiles).toJSONString(0);

        Award award = Award.builder().content(content).title(title).files(addedFilesJson).getTime(getTime)
                .images(addedImagesJson).type(type).staffId(loginStaff.getId()).build();

        boolean saveResult = awardService.save(award);
        if (saveResult) {
            return RestResponse.ok();
        } else {
            for (Integer addedImage: addedImages) {
                fileService.deleteById(addedImage, loginStaff);
            }
            for (Integer addedFile : addedFiles) {
                fileService.deleteById(addedFile, loginStaff);
            }
            return RestResponse.fail(SystemCode.InnerError.getCode(), "存储记录时发生错误");
        }
    }

    @GetMapping("title/{title}/{current}/{size}")
    @ApiOperation("通过标题分页查询奖项信息")
    public RestResponse<AwardPageDTO> selectAwardByTitle(@PathVariable String title,
                                                                 @PathVariable Integer current,
                                                                 @PathVariable Integer size,
                                                                 @ApiIgnore @TokenToStaff Staff loginStaff) {
        QueryWrapper<Award> queryWrapper = new QueryWrapper<>();
        Page<Award> awardPage = new Page<>(current, size);
        if (loginStaff.getRole().getId() > RoleEnum.student.getId()) {
            queryWrapper.lambda().like(Award::getTitle, title);
        } else {
            queryWrapper.lambda().like(Award::getTitle, title).eq(Award::getStaffId, loginStaff.getId());
        }
        Page<Award> page = awardService.page(awardPage, queryWrapper);
        AwardPageDTO<List<AwardSelectDTO>> awardPageDTO = new AwardPageDTO<>();
        awardPageDTO.setHasPre(awardPage.hasPrevious());
        awardPageDTO.setHasNext(awardPage.hasNext());
        List<AwardSelectDTO> returnList = page.getRecords().stream().map(item -> {
            AwardSelectDTO awardSelectDTO = new AwardSelectDTO();
            BeanUtils.copyProperties(item, awardSelectDTO);
            return awardSelectDTO;
        }).collect(Collectors.toList());
        awardPageDTO.setAwardList(returnList);
        return RestResponse.ok(awardPageDTO);
    }

    @GetMapping("{current}/{size}")
    @ApiOperation("分页查询奖项信息")
    public RestResponse<AwardPageDTO<List<AwardSelectDTO>>> selectAwardPages(@PathVariable Integer current, @PathVariable Integer size,
                                                       @ApiIgnore @TokenToStaff Staff loginStaff) {
        Page<Award> page = new Page<>();
        page.setCurrent(current);
        page.setSize(size);
        QueryWrapper<Award> queryWrapper = new QueryWrapper<>();
        if (loginStaff.getRole().getId().equals(RoleEnum.student.getId())) {
            queryWrapper.lambda().eq(Award::getStaffId, loginStaff.getId());
        }
        Page<Award> resultPage = awardService.page(page, queryWrapper);
        List<AwardSelectDTO> collect = resultPage.getRecords().stream().map(item -> {
            AwardSelectDTO awardSelectDTO = new AwardSelectDTO();
            if (loginStaff.getId().equals(item.getStaffId())) {
                awardSelectDTO.setStaffName(loginStaff.getName());
            } else {
                Staff recordStaff = staffService.getById(item.getStaffId());
                awardSelectDTO.setStaffName(recordStaff.getName());
            }
            BeanUtils.copyProperties(item, awardSelectDTO);
            return awardSelectDTO;
        }).collect(Collectors.toList());
        AwardPageDTO<List<AwardSelectDTO>> awardPageDTO = new AwardPageDTO<>(collect, resultPage.hasNext(), resultPage.hasPrevious());
        return RestResponse.ok(awardPageDTO);
    }

    @DeleteMapping("{id}")
    @ApiOperation("删除奖项")
    public RestResponse<String> deleteAward(@PathVariable Integer id,
                                            @ApiIgnore @TokenToStaff Staff loginStaff) {
        Award deleteAward = awardService.getById(id);
        if (loginStaff.getRole().getId().equals(RoleEnum.student.getId())
                && !deleteAward.getStaffId().equals(loginStaff.getId())) {
            return RestResponse.fail(SystemCode.AccessDenied.getCode(), "没有权限删除该奖项");
        }
        boolean deleteResult = awardService.removeById(id);
        if (deleteResult) {
            return RestResponse.ok();
        } else {
            return RestResponse.fail(SystemCode.InnerError.getCode(), "删除该奖项时发生错误");
        }
    }

    @GetMapping("{id}")
    @ApiOperation("根据id获取奖项具体信息")
    public RestResponse getAwardById(@PathVariable Integer id, @ApiIgnore @TokenToStaff Staff loginStaff) {
        Award selectAward = awardService.getById(id);
        if (selectAward == null) {
            return RestResponse.fail(SystemCode.AccessDenied.getCode(), SystemCode.AccessDenied.getMessage());
        } else {
            if (!Objects.equals(selectAward.getStaffId(), loginStaff.getId())
                    && Objects.equals(loginStaff.getRole().getId(), RoleEnum.student.getId())) {
                return RestResponse.fail(SystemCode.AccessDenied.getCode(), SystemCode.AccessDenied.getMessage());
            }
            String imageStr = selectAward.getImages();
            JSONArray objects = JSONUtil.parseArray(imageStr);
            List<Integer> imagesIdList = objects.toList(Integer.class);
            List<String> imageNameList = new LinkedList<>();
            imagesIdList.forEach(item -> {
                File file = fileService.getById(item);
                if (file != null)
                    imageNameList.add(file.getNewName());
            });
            AwardSelectDTO awardSelectDTO = new AwardSelectDTO();
            List<Integer> filesIdList = JSONUtil.parseArray(selectAward.getFiles()).toList(Integer.class);
            List<Map<String, String>> fileList = new LinkedList<>();
            filesIdList.forEach(item -> {
                File file = fileService.getById(item);
                if (file != null) {
                    HashMap<String, String> map = new HashMap<>();
                    map.put("name", file.getOriginName());
                    map.put("url", file.getNewName());
                    fileList.add(map);
                }
            });
            BeanUtils.copyProperties(selectAward, awardSelectDTO);
            awardSelectDTO.setImages(imageNameList);
            awardSelectDTO.setFiles(fileList);
            return RestResponse.ok(awardSelectDTO);
        }
    }

    @PutMapping
    @ApiOperation("更新奖项信息")
    public RestResponse<String> updateAward(@RequestBody AwardUpdateDTO awardUpdateDTO,
                                      @ApiIgnore @TokenToStaff Staff loginStaff) {
        Award updateAward = awardService.getById(awardUpdateDTO.getId());
        if (loginStaff.getRole().getId().equals(RoleEnum.student.getId())
                && !updateAward.getStaffId().equals(loginStaff.getId())) {
            return RestResponse.fail(SystemCode.AccessDenied.getCode(), "没有权限修改该奖项");
        }
        BeanUtils.copyProperties(awardUpdateDTO, updateAward);
        boolean updateResult = awardService.updateById(updateAward);
        if (updateResult) {
            return RestResponse.ok();
        } else {
            return RestResponse.fail(SystemCode.InnerError.getCode(), "修改奖项时发生错误");
        }
    }

    @GetMapping("analysis/{type}")
    @SaCheckRole(value = {"admin", "teacher"}, mode = SaMode.OR)
    @ApiOperation("获取奖项汇总统计信息")
    public RestResponse analysisData(@PathVariable String type) {
        if (type.equals("type")) {
            return awardService.analysisGroupByType();
        } else {
            return awardService.analysisGroupByName();
        }
    }

    @GetMapping("analysis/name/{name}/{current}/{size}")
    @SaCheckRole(value = {"admin", "teacher"}, mode = SaMode.OR)
    @ApiOperation("根据用户姓名进行查询")
    public RestResponse analysisDataByName(@PathVariable String name, @PathVariable Integer current,
                                           @PathVariable Integer size) {
        return awardService.analysisByName(name, current, size);
    }

    @GetMapping("analysis/name/{name}/{current}/{size}/{startTime}/{endTime}")
    @SaCheckRole(value = {"admin", "teacher"}, mode = SaMode.OR)
    @ApiOperation("根据用户姓名进行查询")
    public RestResponse analysisDataByName(@PathVariable String name, @PathVariable Integer current,
                                           @PathVariable Integer size, @PathVariable Date startTime,
                                           @PathVariable Date endTime) {
        return awardService.analysisByNameLimitByDate(name, current, size, startTime, endTime);
    }

    @GetMapping("analysis/{type}/{startTime}/{endTime}")
    @SaCheckRole(value = {"admin", "teacher"}, mode = SaMode.OR)
    @ApiOperation("根据时间范围获取奖项汇总信息")
    public RestResponse analysisDateLimitByDate(@PathVariable String type, @PathVariable Date startTime, @PathVariable Date endTime) {
        if (type.equals("type")) {
            return awardService.analysisGroupByTypeLimitByDate(startTime, endTime);
        } else {
            return awardService.analysisGroupByStaffNameLimitByDate(startTime, endTime);
        }
    }

    @GetMapping("id/{staffId}/{startTime}/{endTime}/{current}/{size}")
    @SaCheckRole(value = {"admin", "teacher"}, mode = SaMode.OR)
    @ApiOperation("根据时间范围和用户id分页获取用户奖项信息列表")
    public RestResponse getStaffAwardsLimitByDatePage(@PathVariable Integer staffId,
                                                  @PathVariable Integer current,
                                                  @PathVariable Integer size,
                                                  @PathVariable Date startTime,
                                                  @PathVariable Date endTime) {
        Staff staff = staffService.getById(staffId);
        if (staff != null) {
            return awardService.getStaffAwardsLimitByDatePage(staff, current, size, startTime, endTime);
        } else {
            return RestResponse.fail(SystemCode.AccessDenied.getCode(), SystemCode.AccessDenied.getMessage());
        }
    }

    @GetMapping("id/{staffId}/date/{startTime}/{endTime}")
    @SaCheckRole(value = {"admin", "teacher"}, mode = SaMode.OR)
    @ApiOperation("根据时间范围和用户id获取用户奖项信息列表")
    public RestResponse getStaffAwardsLimitByDate(@PathVariable Integer staffId,
                                                  @PathVariable Date startTime,
                                                  @PathVariable Date endTime) {
        Staff staff = staffService.getById(staffId);
        if (staff != null) {
            return awardService.getStaffAwardsLimitByDate(staff, startTime, endTime);
        } else {
            return RestResponse.fail(SystemCode.AccessDenied.getCode(), SystemCode.AccessDenied.getMessage());
        }
    }

    @GetMapping("id/{staffId}")
    @SaCheckRole(value = {"admin", "teacher"}, mode = SaMode.OR)
    @ApiOperation("根据用户id获取用户奖项信息列表")
    public RestResponse getStaffAwards(@PathVariable Integer staffId) {
        Staff staff = staffService.getById(staffId);
        if (staff != null) {
            return awardService.getStaffAwards(staff);
        } else {
            return RestResponse.fail(SystemCode.AccessDenied.getCode(), SystemCode.AccessDenied.getMessage());
        }
    }

    @GetMapping("analysis/id/{staffId}/date/{startTime}/{endTime}")
    @SaCheckRole(value = {"admin", "teacher"}, mode = SaMode.OR)
    @ApiOperation("根据时间范围和用户id获取用户奖项分析信息")
    public RestResponse getStaffAwardAnalysisLimitByDate(@PathVariable Integer staffId,
                                                         @PathVariable Date startTime,
                                                         @PathVariable Date endTime) {
        Staff staff = staffService.getById(staffId);
        if (staff != null) {
            return awardService.getStaffAwardAnalysisLimitByDate(staff, startTime, endTime);
        } else {
            return RestResponse.fail(SystemCode.AccessDenied.getCode(), SystemCode.AccessDenied.getMessage());
        }
    }

    @GetMapping("analysis/id/{staffId}")
    @SaCheckRole(value = {"admin", "teacher"}, mode = SaMode.OR)
    @ApiOperation("根据用户id获取用户奖项分析信息")
    public RestResponse getStaffAwardAnalysis(@PathVariable Integer staffId) {
        Staff staff = staffService.getById(staffId);
        if (staff != null) {
            return awardService.getStaffAwardAnalysis(staff);
        } else {
            return RestResponse.fail(SystemCode.AccessDenied.getCode(), SystemCode.AccessDenied.getMessage());
        }
    }
}

